﻿namespace Rage.UI
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Media.Imaging;
    using System.Windows.Data;
    using System.ComponentModel;
    using System.Threading;
    using System.Windows.Threading;
    using Microsoft.Win32;
    using GomLib.Models;
    using GomTest.GenTalents;
    using System.Text.RegularExpressions;
    using System.IO;

    public partial class DG_ToRLoader_Ability : ChildWindow
    {
        public DG_ToRLoader_Ability()
        {
            InitializeComponent();

            DG_ProgressBar = new UI.DG_ProgressBar();
            DG_ProgressBar.Closed += new EventHandler(DG_ProgressBar_Closed);

            BackgroundWorker _backgroundWorker = new BackgroundWorker();

            // Set up the Background Worker Events
            _backgroundWorker.DoWork += _backgroundWorker_DoWork;
            _backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted;

            // Run the Background Worker
            _backgroundWorker.RunWorkerAsync(250);

            // Create the thread and kick it started!
            //new Thread(start).Start();
            DG_ProgressBar.Show();
        }

        DG_ProgressBar DG_ProgressBar;

        List<GomLib.Models.Ability> abils = new List<GomLib.Models.Ability>();

        // Worker Method
        private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            // Do something
            GomLib.DataObjectModel.Load();
            var abilList = GomLib.DataObjectModel.GetObjectsStartingWith("abl.");
            abilList = abilList.Where(obj => !obj.Name.EndsWith(@"/0")
                                          && !obj.Name.EndsWith(@"/1")
                                          && !obj.Name.EndsWith(@"/2")
                                          && !obj.Name.EndsWith(@"/3")
                                          && !obj.Name.EndsWith(@"/4")
                                          && !obj.Name.EndsWith(@"/5")
                                          && !obj.Name.EndsWith(@"/6")
                                          && !obj.Name.EndsWith(@"/7")
                                          && !obj.Name.EndsWith(@"/8")
                                          && !obj.Name.EndsWith(@"/9")).ToList();
            abilList = abilList.OrderBy(obj => obj.Name).ToList();
            abilList = abilList.Where(obj => obj.Name.StartsWith("abl.agent")
                                          || obj.Name.StartsWith("abl.ballistics")
                                          || obj.Name.StartsWith("abl.bounty_hunter")
                                          || obj.Name.StartsWith("abl.flurry.jedi_consular")
                                          || obj.Name.StartsWith("abl.jedi_consular")
                                          || obj.Name.StartsWith("abl.flurry.jedi_knight")
                                          || obj.Name.StartsWith("abl.jedi_knight")
                                          || obj.Name.StartsWith("abl.racials")
                                          || obj.Name.StartsWith("abl.flurry.sith_inquisitor")
                                          || obj.Name.StartsWith("abl.sith_inquisitor")
                                          || obj.Name.StartsWith("abl.flurry.sith_warrior")
                                          || obj.Name.StartsWith("abl.sith_warrior")
                                          || obj.Name.StartsWith("abl.smuggler")
                                          || obj.Name.StartsWith("abl.trooper")
                                      ).ToList();
            //abilList = abilList.Where(obj => obj.Name.Contains("ravage")).ToList();
            double i = 0;
            double cntSkipped = 0;
            double ttl = abilList.Count();
            Dispatcher.BeginInvoke((Action) delegate {
                DG_ProgressBar.UpdateProgress(i, ttl, cntSkipped/*, itm.Name*/);
                //DG_ProgressBar.AddLineToLog(itm.Name + " : Completed");
            });
            foreach (var gomAbil in abilList)
            {
                GomLib.Models.Ability abil = new GomLib.Models.Ability();
                try {
                    GomLib.ModelLoader.AbilityLoader.Load(abil, gomAbil);
                } catch (Exception) {
                    continue;
                }
                bool addIt = true;
#if FALSE
                #region Filter by Invalid Item Type
                if (addIt)
                {
                    switch (abil.SubCategory)
                    {
                        case GomLib.Models.ItemSubCategory.Undefined:
                        case GomLib.Models.ItemSubCategory.OtherQuestItem:
                        case GomLib.Models.ItemSubCategory.OtherLockbox:
                        case GomLib.Models.ItemSubCategory.OtherCustomization:
                        case GomLib.Models.ItemSubCategory.OtherGift:
                        case GomLib.Models.ItemSubCategory.OtherCurrency:
                        case GomLib.Models.ItemSubCategory.OtherMount:
                        case GomLib.Models.ItemSubCategory.OtherPet:
                        case GomLib.Models.ItemSubCategory.CraftingMaterial:
                        case GomLib.Models.ItemSubCategory.CraftingSchematic:
                        case GomLib.Models.ItemSubCategory.ConsumableAdrenal:
                        case GomLib.Models.ItemSubCategory.ConsumableMedpac:
                        case GomLib.Models.ItemSubCategory.ConsumableStim:
                        case GomLib.Models.ItemSubCategory.ConsumableFood:
                        case GomLib.Models.ItemSubCategory.ConsumablePvp:
                        case GomLib.Models.ItemSubCategory.ConsumableGrenade:
                        case GomLib.Models.ItemSubCategory.EquipmentDroidPart:
                        case GomLib.Models.ItemSubCategory.OtherUnknown:
                        case GomLib.Models.ItemSubCategory.EquipmentSpace:
                            { addIt = false; break; }
                        default: { break; }
                    }
                }
                #endregion
                #region Filter by Low Quality
                if (addIt)
                {
                    switch (abil.Quality)
                    {
                        case GomLib.Models.ItemQuality.Cheap:
                        case GomLib.Models.ItemQuality.Standard:
                        //case GomLib.Models.ItemQuality.Premium:
                        //case GomLib.Models.ItemQuality.Prototype:
                        //case GomLib.Models.ItemQuality.Artifact:
                        //case GomLib.Models.ItemQuality.Legendary:
                        //case GomLib.Models.ItemQuality.Legacy:
                        case GomLib.Models.ItemQuality.Quest:
                        case GomLib.Models.ItemQuality.Currency:
                        //case GomLib.Models.ItemQuality.Moddable:
                            { addIt = false; break; }
                        default: {  break; }
                    }
                }
                #endregion
                #region Filter by Low Item Level
                if (addIt)
                {
                    if (abil.SubCategory == GomLib.Models.ItemSubCategory.ItemModColorCrystal) {
                        if (abil.ItemLevel < 40) { addIt = false; }
                    } else if (abil.SubCategory == GomLib.Models.ItemSubCategory.ItemModArmoring
                        || abil.SubCategory == GomLib.Models.ItemSubCategory.ItemModAugment
                        || abil.SubCategory == GomLib.Models.ItemSubCategory.ItemModMod
                        || abil.SubCategory == GomLib.Models.ItemSubCategory.ItemModEnhancement
                        || abil.SubCategory == GomLib.Models.ItemSubCategory.ItemModBarrel
                        || abil.SubCategory == GomLib.Models.ItemSubCategory.ItemModHilt
                        ) {
                        if (abil.ItemLevel < 45) { addIt = false; }
                    } else {
                        if (abil.ItemLevel < 48) { addIt = false; }
                    }
                }
                #endregion
                #region Filter by bad names
                if (addIt && string.IsNullOrEmpty(abil.Name)) { addIt = false; }
                if (addIt)
                {
                    List<String> badStartsWithValues = new List<String>()
                    {
                        "TBD",
                        "Andronikos Revel",
                        "Ashara",
                        "Blizz",
                        "Bowdaar",
                        "Broonmark",
                        "Corso",
                        "Doc",
                        "Elara",
                        "Gault",
                        "Guss Tuno",
                        "Iresso",
                        "Jaesa",
                        "Jorgan",
                        "Kaliyo",
                        "Khem Val",
                        "Kira",
                        "Lokin",
                        "Mako",
                        "Nadia",
                        "Pierce",
                        "Quinn",
                        "Qyzen",
                        "Risha",
                        "Rusk",
                        "Scourge",
                        "Skadge",
                        "Spar",
                        "Talos",
                        "Tanno",
                        "Temple",
                        "Tharan",
                        "Torian",
                        "Vector",
                        "Vette",
                        "Vik",
                        "Xalek",
                        "Yuun",
                        "Zenith",
                        "Zez-Kai Ell",
                    };
                    foreach(string s in badStartsWithValues) {
                        if (abil.Name.StartsWith(s)) { addIt = false; break; }
                    }
                }
                #endregion
#endif
                if (addIt) { abils.Add(abil); } else { cntSkipped++; }
                Dispatcher.BeginInvoke((Action) delegate {
                    DG_ProgressBar.UpdateProgress(i, ttl, cntSkipped);
                });
                i++;
            }
            view = new ListCollectionView(abils);
            BuildAbilityInfoScript(abils);
            //view.GroupDescriptions.Add(new PropertyGroupDescription("Category"));
            //view.GroupDescriptions.Add(new PropertyGroupDescription("SubCategory"));
            //view.GroupDescriptions.Add(new PropertyGroupDescription("ItemLevel"));
            //view.SortDescriptions.Add(new SortDescription("Id", ListSortDirection.Ascending));
            //view.SortDescriptions.Add(new SortDescription("SubCategory", ListSortDirection.Ascending));
        }
        ListCollectionView view;

        public string GetSimpleName(string source)
        {
            return  source.Replace(" ", "").Replace("-", "").Replace("\'", "")
                          .Replace("_", "").Replace(":", "").Replace(".", "")
                          .Replace("!", "");
        }

        public List<string> SpecialEffectsParser(string line)
        {
            Regex regex = new Regex("");
            Match m = regex.Match(line);
            List<string> retVals = new List<string>();
            // Invincible
            if ((m = new Regex(@"Reduces all damage taken by (?<value>\d+)% for (?<duration>\d+)*Pts second").Match(line)).Success)
            {
                retVals.Add(string.Format("new SpecialEffect(Rage.Trigger.{0}, new Stats() { DamageTakenReductionMultiplier = {1:0.##}f, }, {2:0.##}f, {3:0.##}f);",
                    Rage.Trigger.Use, (float)int.Parse(m.Groups["value"].Value) / 100f,
                    int.Parse(m.Groups["duration"].Value), 180f)
                );
            }
            // Endure Pain
            if ((m = new Regex(@"Temporarily increases your maximum health by (?<value>\d+)% for (?<duration>\d+)*Pts second").Match(line)).Success)
            {
                retVals.Add(string.Format("new SpecialEffect(Rage.Trigger.{0}, new Stats() { BonusHealthMultiplier = {1:0.##}f, }, {2:0.##}f, {3:0.##}f);",
                    Rage.Trigger.Use, (float)int.Parse(m.Groups["value"].Value) / 100f, int.Parse(m.Groups["duration"].Value), 180f)
                );
            }
            // Saber Ward
            if ((m = new Regex(@"Raises a lightsaber ward, increasing melee and ranged defenses by (?<value1>\d+)% and reducing the damage taken from Force and tech attacks by (?<value2>\d+)%. Lasts (?<duration>\d+)*Pts second").Match(line)).Success)
            {
                retVals.Add(string.Format("new SpecialEffect(Rage.Trigger.{0}, new Stats() { Defense = {1:0.##}f, DamageTakenReductionMultiplier = {2:0.##}f, }, {3:0.##}f, {4:0.##}f);",
                    Rage.Trigger.Use, (float)int.Parse(m.Groups["value1"].Value) / 100f, (float)int.Parse(m.Groups["value2"].Value) / 100f, int.Parse(m.Groups["duration"].Value), 180f)
                );
            }
            //
            return retVals;
        }

        public List<string> AbilityDamageChangesParsing(string line)
        {
            Regex regex = new Regex("");
            Match m = regex.Match(line);
            List<string> retVals = new List<string>();
            // Cannot miss, be parried or dodged.
            if ((m = new Regex(@"Cannot miss, be parried or dodged").Match(line)).Success)
            {
                retVals.Add("CanMiss = false;");
                retVals.Add("CanBeDodged = false;");
                retVals.Add("CanBeParried = false;");
            }
            // use Offhand if available
            if ((m = new Regex(@"(Strikes|Attacks) with both (weapons|lightsabers) if dual wielding").Match(line)).Success)
            {
                retVals.Add("CallsForOffhand = true;");
            }
            if ((m = new Regex(@"up to (?<count>\d+) enemies").Match(line)).Success)
            {
                retVals.Add(string.Format("Targets = {0};", int.Parse(m.Groups["count"].Value)));
            }
            if ((m = new Regex(@"high amount of threat").Match(line)).Success)
            {
                retVals.Add("HighThreat = true;");
            }
            if ((m = new Regex(@"Only usable on incapacitated targets").Match(line)).Success)
            {
                retVals.Add("MustTargetIncapacitated = true;");
            }
            if ((m = new Regex(@"Only usable on slowed or immobilized targets").Match(line)).Success)
            {
                retVals.Add("MustTargetSlowedOrImmobilized = true;");
            }
            //
            return retVals;
        }

        public void BuildAbilityInfoScript(List<GomLib.Models.Ability> abilityList)
        {
            #region Declare Variables, Assign Lists, Prep Output Files
            Dictionary<string, List<GomLib.Models.Ability> > abilLists = new Dictionary<string, List<GomLib.Models.Ability> >();
            Dictionary<string, string> outFilePaths = new Dictionary<string, string>();
            Dictionary<string, FileStream> outFiles = new Dictionary<string, FileStream>();
            Dictionary<string, StreamWriter> writers = new Dictionary<string, StreamWriter>();
            //
            abilLists["all"] = abilityList;
            abilLists["agent"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("agent")).ToList();
            abilLists["ballistics"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("ballistics")).ToList();
            abilLists["bounty_hunter"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("bounty_hunter")).ToList();
            abilLists["jedi_consular"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("jedi_consular")).ToList();
            abilLists["jedi_knight"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("jedi_knight")).ToList();
            abilLists["racials"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("racials")).ToList();
            abilLists["sith_inquisitor"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("sith_inquisitor")).ToList();
            abilLists["sith_warrior"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("sith_warrior")).ToList();
            abilLists["smuggler"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("smuggler")).ToList();
            abilLists["trooper"] = abilityList.Where(i => (i.Fqn.Contains('.') ? i.Fqn.Split('.')[1] : i.Fqn).Contains("trooper")).ToList();
            //
            foreach (string k in abilLists.Keys)
            {
                outFilePaths[k] = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "ClassAbilityData."+k.Replace("_", "").ToLowerInvariant().Replace(" ", "")+".cs");
                outFiles[k] = System.IO.File.Open(outFilePaths[k], System.IO.FileMode.Create, System.IO.FileAccess.Write);
                writers[k] = new System.IO.StreamWriter(outFiles[k]);
            }
            #endregion
            #region Write Header to every file
            foreach (string k in abilLists.Keys)
            {
                if (k == "all")
                {
                writers[k].WriteLine("namespace Rage.Base.Abilities");
                }
                else
                {
                writers[k].WriteLine("namespace Rage.Base.Abilities." + k);
                }
                writers[k].WriteLine("{");
                writers[k].WriteLine("    using System;");
                writers[k].WriteLine("    using System.Collections.Generic;");
                writers[k].WriteLine("    using System.Reflection;");
                writers[k].WriteLine("    using System.Text;");
                writers[k].WriteLine("");
                writers[k].WriteLine("    // This file is automatically generated by the Rage.AbilityClassGenerator tool. Please don't edit it directly.");
                writers[k].WriteLine("");
                if (k != "all") {
                writers[k].WriteLine("    #region " + k);
                }
            }
            #endregion
            #region Write Ability to [key] file
            List<string> abilsReadAlready = new List<string>();
            abilsReadAlready.Clear();
            for (int a = 0; a < abilityList.Count; a++)
            {
                Ability ab = abilityList[a];
                string simpleName = GetSimpleName(ab.Name);
                string k = (ab.Fqn.Contains('.') ? (ab.Fqn.Contains(".flurry.") ? ab.Fqn.Split('.')[2] : ab.Fqn.Split('.')[1]) : k = ab.Fqn);

                //if (!abilLists.Keys.Contains(k)) { continue; } // prevent errors but should never happen

                if (abilsReadAlready.Contains(k + "." + simpleName)) {
                    simpleName = simpleName + (abilsReadAlready.Where(i => i == (k + "." + simpleName)).Count() + 1);
                }
                abilsReadAlready.Add((k + "." + simpleName).Clone() as string);
                #region Declare Ability Variables
                string desc = ab.Description.Trim();
                //
                string DamageCoreType1 = ""; float DamageCoreMultiplier1 = 0, DamageCoreCoeff1 = 0, DamageCoreHPMin1 = 0, DamageCoreHPMax1 = 0, DamageCoreModPct1 = 0, DamageCoreFlurryBlowsMin1 = 0, DamageCoreFlurryBlowsMax1 = 0, DamageCoreThreatMod1 = 0, DamageCoreModFixedMin1 = 0, DamageCoreModFixedMax1 = 0;
                string DamageCoreType2 = ""; float DamageCoreMultiplier2 = 0, DamageCoreCoeff2 = 0, DamageCoreHPMin2 = 0, DamageCoreHPMax2 = 0, DamageCoreModPct2 = 0, DamageCoreFlurryBlowsMin2 = 0, DamageCoreFlurryBlowsMax2 = 0, DamageCoreThreatMod2 = 0, DamageCoreModFixedMin2 = 0, DamageCoreModFixedMax2 = 0;
                string DamageCoreType3 = ""; float DamageCoreMultiplier3 = 0, DamageCoreCoeff3 = 0, DamageCoreHPMin3 = 0, DamageCoreHPMax3 = 0, DamageCoreModPct3 = 0, DamageCoreFlurryBlowsMin3 = 0, DamageCoreFlurryBlowsMax3 = 0, DamageCoreThreatMod3 = 0, DamageCoreModFixedMin3 = 0, DamageCoreModFixedMax3 = 0;
                string DamageCoreType4 = ""; float DamageCoreMultiplier4 = 0, DamageCoreCoeff4 = 0, DamageCoreHPMin4 = 0, DamageCoreHPMax4 = 0, DamageCoreModPct4 = 0, DamageCoreFlurryBlowsMin4 = 0, DamageCoreFlurryBlowsMax4 = 0, DamageCoreThreatMod4 = 0, DamageCoreModFixedMin4 = 0, DamageCoreModFixedMax4 = 0;
                string DamageCoreType5 = ""; float DamageCoreMultiplier5 = 0, DamageCoreCoeff5 = 0, DamageCoreHPMin5 = 0, DamageCoreHPMax5 = 0, DamageCoreModPct5 = 0, DamageCoreFlurryBlowsMin5 = 0, DamageCoreFlurryBlowsMax5 = 0, DamageCoreThreatMod5 = 0, DamageCoreModFixedMin5 = 0, DamageCoreModFixedMax5 = 0;
                string DamageCoreType6 = ""; float DamageCoreMultiplier6 = 0, DamageCoreCoeff6 = 0, DamageCoreHPMin6 = 0, DamageCoreHPMax6 = 0, DamageCoreModPct6 = 0, DamageCoreFlurryBlowsMin6 = 0, DamageCoreFlurryBlowsMax6 = 0, DamageCoreThreatMod6 = 0, DamageCoreModFixedMin6 = 0, DamageCoreModFixedMax6 = 0;
                string DamageCoreType7 = ""; float DamageCoreMultiplier7 = 0, DamageCoreCoeff7 = 0, DamageCoreHPMin7 = 0, DamageCoreHPMax7 = 0, DamageCoreModPct7 = 0, DamageCoreFlurryBlowsMin7 = 0, DamageCoreFlurryBlowsMax7 = 0, DamageCoreThreatMod7 = 0, DamageCoreModFixedMin7 = 0, DamageCoreModFixedMax7 = 0;
                string DamageCoreType8 = ""; float DamageCoreMultiplier8 = 0, DamageCoreCoeff8 = 0, DamageCoreHPMin8 = 0, DamageCoreHPMax8 = 0, DamageCoreModPct8 = 0, DamageCoreFlurryBlowsMin8 = 0, DamageCoreFlurryBlowsMax8 = 0, DamageCoreThreatMod8 = 0, DamageCoreModFixedMin8 = 0, DamageCoreModFixedMax8 = 0;
                string DamageCoreType9 = ""; float DamageCoreMultiplier9 = 0, DamageCoreCoeff9 = 0, DamageCoreHPMin9 = 0, DamageCoreHPMax9 = 0, DamageCoreModPct9 = 0, DamageCoreFlurryBlowsMin9 = 0, DamageCoreFlurryBlowsMax9 = 0, DamageCoreThreatMod9 = 0, DamageCoreModFixedMin9 = 0, DamageCoreModFixedMax9 = 0;
                string DamageCoreType10 = ""; float DamageCoreMultiplier10 = 0, DamageCoreCoeff10 = 0, DamageCoreHPMin10 = 0, DamageCoreHPMax10 = 0, DamageCoreModPct10 = 0, DamageCoreFlurryBlowsMin10 = 0, DamageCoreFlurryBlowsMax10 = 0, DamageCoreThreatMod10 = 0, DamageCoreModFixedMin10 = 0, DamageCoreModFixedMax10 = 0;
                
                float HealingCoreMultiplier = 0;
                float HealingCoreHPMin = 0;
                float HealingCoreHPMax = 0;
                float HealingCoreMultiplier2 = 0;
                float HealingCoreCoeff2 = 0;
                float HealingCoreHPMin2 = 0;
                float HealingCoreHPMax2 = 0;
                float Duration = 0;
                float Rank = 0;
                #endregion
                #region Parse Ability Tokens if available
                if (!string.IsNullOrEmpty(ab.AbilityTokens))
                {
                    List<string> tokens = new List<string>(ab.AbilityTokens.Split(';'));
                    List<string> values = new List<string>();
                    List<bool> dontparse = new List<bool>();
                    int cur = 0;
                    foreach (string token in tokens)
                    {
                        #region Declare some Regexes
                        // damage,0,0,0,w,1,3.29,0.329,0.329,0,0,1.2
                        Regex DamageType = new Regex(@"(?<maintype>damage),"                // damage
                                                    + @"(?<flurrMin>-?\d+(?:\.\d+)?),"      // 0
                                                    + @"(?<flurrMax>-?\d+(?:\.\d+)?),"      // 0
                                                    + @"(?<threatPerc>-?\d+(?:\.\d+)?),"    // 0
                                                    + @"(?<type>w|s),"                      // w
                                                    + @"(?<multi>-?\d+(?:\.\d+)?),"         // 1
                                                    + @"(?<coeff>-?\d+(?:\.\d+)?),"         // 3.29
                                                    + @"(?<stdHpMin>-?\d+(?:\.\d+)?),"      // 0.329
                                                    + @"(?<stdHpMax>-?\d+(?:\.\d+)?),"      // 0.329
                                                    + @"(?<modFMin>-?\d+(?:\.\d+)?),"        // 0
                                                    + @"(?<modFMax>-?\d+(?:\.\d+)?),"        // 0
                                                    + @"(?<modPct>-?\d+(?:\.\d+)?)");       // 1.2
                        // "healing,1,2.37,0.098,0.138"
                        Regex HealingTypeA = new Regex(@"(?<maintype>healing)," // healing,
                                                    + @"(?<multiplier>\d+(?:\.\d+)?)," // 1,
                                                    + @"(?<HPMin>\d+(?:\.\d+)?)," // 0.098,
                                                    + @"(?<HPMax>\d+(?:\.\d+)?)"); // 0.138,
                        Regex HealingTypeB = new Regex(@"(?<maintype>healing)," // healing,
                                                    + @"(?<multiplier>\d+(?:\.\d+)?)," // 1,
                                                    + @"(?<APcoeff>\d+(?:\.\d+)?)," //  2.37,
                                                    + @"(?<HPMin>\d+(?:\.\d+)?)," // 0.098,
                                                    + @"(?<HPMax>\d+(?:\.\d+)?)"); // 0.138,
                        Regex DurationType = new Regex(@"(?<type>duration),(?<value>\d+)");
                        Regex RankType = new Regex(@"(?<type>rank),(?<value>\d+)");
                        Match m;
                        #endregion
                        if ((m = DamageType.Match(token)).Success) {
                            #region Damages with no core coeff
                            cur++;
                            float flurrMin = float.Parse(m.Groups["flurrMin"].Value);
                            float flurrMax = float.Parse(m.Groups["flurrMax"].Value);
                            float threatPerc = float.Parse(m.Groups["threatPerc"].Value);
                            string type = m.Groups["type"].Value;
                            float multi = float.Parse(m.Groups["multi"].Value);
                            float coeff = float.Parse(m.Groups["coeff"].Value);
                            float stdHpMin = float.Parse(m.Groups["stdHpMin"].Value);
                            float stdHpMax = float.Parse(m.Groups["stdHpMax"].Value);
                            float modFMin = float.Parse(m.Groups["modFMin"].Value);
                            float modFMax = float.Parse(m.Groups["modFMax"].Value);
                            float modPct = float.Parse(m.Groups["modPct"].Value);
                            string format = "{0:0.##%}*({1:0.##}*charDmgBonuses+{2:0.##}*StdDmg)";
                            string minDmg = "";
                            string maxDmg = "";
                            switch (cur)
                            {
                                case 1: { DamageCoreType1 = type; DamageCoreMultiplier1 = multi; DamageCoreCoeff1 = coeff; DamageCoreHPMin1 = stdHpMin; DamageCoreHPMax1 = stdHpMax; DamageCoreModPct1 = modPct;
                                    DamageCoreFlurryBlowsMin1 = flurrMin; DamageCoreFlurryBlowsMax1 = flurrMax; DamageCoreThreatMod1 = threatPerc; DamageCoreModFixedMin1 = modFMin; DamageCoreModFixedMax1 = modFMax; break; }
                                case 2: { DamageCoreType2 = type; DamageCoreMultiplier2 = multi; DamageCoreCoeff2 = coeff; DamageCoreHPMin2 = stdHpMin; DamageCoreHPMax2 = stdHpMax; DamageCoreModPct2 = modPct;
                                    DamageCoreFlurryBlowsMin2 = flurrMin; DamageCoreFlurryBlowsMax2 = flurrMax; DamageCoreThreatMod2 = threatPerc; DamageCoreModFixedMin2 = modFMin; DamageCoreModFixedMax2 = modFMax; break; }
                                case 3: { DamageCoreType3 = type; DamageCoreMultiplier3 = multi; DamageCoreCoeff3 = coeff; DamageCoreHPMin3 = stdHpMin; DamageCoreHPMax3 = stdHpMax; DamageCoreModPct3 = modPct;
                                    DamageCoreFlurryBlowsMin3 = flurrMin; DamageCoreFlurryBlowsMax3 = flurrMax; DamageCoreThreatMod3 = threatPerc; DamageCoreModFixedMin3 = modFMin; DamageCoreModFixedMax3 = modFMax; break; }
                                case 4: { DamageCoreType4 = type; DamageCoreMultiplier4 = multi; DamageCoreCoeff4 = coeff; DamageCoreHPMin4 = stdHpMin; DamageCoreHPMax4 = stdHpMax; DamageCoreModPct4 = modPct;
                                    DamageCoreFlurryBlowsMin4 = flurrMin; DamageCoreFlurryBlowsMax4 = flurrMax; DamageCoreThreatMod4 = threatPerc; DamageCoreModFixedMin4 = modFMin; DamageCoreModFixedMax4 = modFMax; break; }
                                case 5: { DamageCoreType5 = type; DamageCoreMultiplier5 = multi; DamageCoreCoeff5 = coeff; DamageCoreHPMin5 = stdHpMin; DamageCoreHPMax5 = stdHpMax; DamageCoreModPct5 = modPct;
                                    DamageCoreFlurryBlowsMin5 = flurrMin; DamageCoreFlurryBlowsMax5 = flurrMax; DamageCoreThreatMod5 = threatPerc; DamageCoreModFixedMin5 = modFMin; DamageCoreModFixedMax5 = modFMax; break; }
                                case 6: { DamageCoreType6 = type; DamageCoreMultiplier6 = multi; DamageCoreCoeff6 = coeff; DamageCoreHPMin6 = stdHpMin; DamageCoreHPMax6 = stdHpMax; DamageCoreModPct6 = modPct;
                                    DamageCoreFlurryBlowsMin6 = flurrMin; DamageCoreFlurryBlowsMax6 = flurrMax; DamageCoreThreatMod6 = threatPerc; DamageCoreModFixedMin6 = modFMin; DamageCoreModFixedMax6 = modFMax; break; }
                                case 7: { DamageCoreType7 = type; DamageCoreMultiplier7 = multi; DamageCoreCoeff7 = coeff; DamageCoreHPMin7 = stdHpMin; DamageCoreHPMax7 = stdHpMax; DamageCoreModPct7 = modPct;
                                    DamageCoreFlurryBlowsMin7 = flurrMin; DamageCoreFlurryBlowsMax7 = flurrMax; DamageCoreThreatMod7 = threatPerc; DamageCoreModFixedMin7 = modFMin; DamageCoreModFixedMax7 = modFMax; break; }
                                case 8: { DamageCoreType8 = type; DamageCoreMultiplier8 = multi; DamageCoreCoeff8 = coeff; DamageCoreHPMin8 = stdHpMin; DamageCoreHPMax8 = stdHpMax; DamageCoreModPct8 = modPct;
                                    DamageCoreFlurryBlowsMin8 = flurrMin; DamageCoreFlurryBlowsMax8 = flurrMax; DamageCoreThreatMod8 = threatPerc; DamageCoreModFixedMin8 = modFMin; DamageCoreModFixedMax8 = modFMax; break; }
                                case 9: { DamageCoreType9 = type; DamageCoreMultiplier9 = multi; DamageCoreCoeff9 = coeff; DamageCoreHPMin9 = stdHpMin; DamageCoreHPMax9 = stdHpMax; DamageCoreModPct9 = modPct;
                                    DamageCoreFlurryBlowsMin9 = flurrMin; DamageCoreFlurryBlowsMax9 = flurrMax; DamageCoreThreatMod9 = threatPerc; DamageCoreModFixedMin9 = modFMin; DamageCoreModFixedMax9 = modFMax; break; }
                                case 10: { DamageCoreType10 = type; DamageCoreMultiplier10 = multi; DamageCoreCoeff10 = coeff; DamageCoreHPMin10 = stdHpMin; DamageCoreHPMax10 = stdHpMax; DamageCoreModPct10 = modPct;
                                    DamageCoreFlurryBlowsMin10 = flurrMin; DamageCoreFlurryBlowsMax10 = flurrMax; DamageCoreThreatMod10 = threatPerc; DamageCoreModFixedMin10 = modFMin; DamageCoreModFixedMax10 = modFMax; break; }
                                default:
                                    {
                                    MessageBox.Show("Whoopsie!");
                                    break;
                                }
                            }
                            minDmg = string.Format(format, multi, coeff, stdHpMin);
                            maxDmg = string.Format(format, multi, coeff, stdHpMax);
                            values.Add(string.Format("{0}-{1}", minDmg, maxDmg));
                            // where stdDmg is a value from the lookup table cbtStandardDamageInfo (that's a node name)
                            dontparse.Add(true);
                            #endregion
                        } else  if ((m = HealingTypeA.Match(token)).Success) {
                            #region Healing
                            HealingCoreMultiplier = float.Parse(m.Groups["multiplier"].Value);
                            HealingCoreHPMin = float.Parse(m.Groups["HPMin"].Value);
                            HealingCoreHPMax = float.Parse(m.Groups["HPMax"].Value);
                            string minHlg = string.Format("{0:0.##%}*({1:0.##}*charHlgBonuses)", HealingCoreMultiplier, HealingCoreHPMin);
                            string maxHlg = string.Format("{0:0.##%}*({1:0.##}*charHlgBonuses)", HealingCoreMultiplier, HealingCoreHPMax);
                            values.Add(string.Format("{0}-{1}", minHlg, maxHlg));
                            // where stdDmg is a value from the lookup table cbtStandardDamageInfo (that's a node name)
                            dontparse.Add(true);
                            #endregion
                        } else  if ((m = HealingTypeB.Match(token)).Success) {
                            #region Healing
                            HealingCoreMultiplier2 = float.Parse(m.Groups["multiplier"].Value);
                            HealingCoreCoeff2 = float.Parse(m.Groups["APcoeff"].Value);
                            HealingCoreHPMin2 = float.Parse(m.Groups["HPMin"].Value);
                            HealingCoreHPMax2 = float.Parse(m.Groups["HPMax"].Value);
                            string minHlg = string.Format("{0:0.##%}*({1:0.##}*charHlgBonuses+{2:0.##}*StdHlg)", HealingCoreMultiplier2, HealingCoreCoeff2, HealingCoreHPMin2);
                            string maxHlg = string.Format("{0:0.##%}*({1:0.##}*charHlgBonuses+{2:0.##}*StdHlg)", HealingCoreMultiplier2, HealingCoreCoeff2, HealingCoreHPMax2);
                            values.Add(string.Format("{0}-{1}", minHlg, maxHlg));
                            // where stdDmg is a value from the lookup table cbtStandardDamageInfo (that's a node name)
                            dontparse.Add(true);
                            #endregion
                        } else if ((m = DurationType.Match(token)).Success) {
                            #region Duration
                            Duration = float.Parse(m.Groups["value"].Value);
                            values.Add(string.Format("{0}", Duration));
                            dontparse.Add(false);
                            #endregion
                        } else if ((m = RankType.Match(token)).Success) {
                            #region Talent Rank based
                            Rank = float.Parse(m.Groups["value"].Value);
                            values.Add(string.Format("{0}", Rank));
                            dontparse.Add(false);
                            #endregion
                        } else {
                            // Didn't Parse
                        }
                    }

                    #region Do the replacements
                    for (int i = 0; i < values.Count; i++)
                    {
                        if (string.IsNullOrEmpty(values[i])) { continue; }
                        desc = desc.Replace(string.Format("<<{0}>>", i + 1),
                            (dontparse[i] ? values[i] : double.Parse(values[i]).ToString() + "*Pts"));
                        desc = desc.Replace(string.Format("<<{0}[%d/%d/%d]>>", i + 1),
                            (dontparse[i] ? values[i] : double.Parse(values[i]).ToString() + "*Pts"));
                        desc = desc.Replace(string.Format("<<{0}[%d%/%d%/%d%]>>", i + 1),
                            (dontparse[i] ? values[i] : double.Parse(values[i]).ToString() + "*Pts"));
                        desc = desc.Replace(string.Format("<<{0}[$d point/$d point/$d points]>>", i + 1),
                            (dontparse[i] ? values[i] : double.Parse(values[i]).ToString() + "*Pts point(s)"));
                        desc = desc.Replace(string.Format("<<{0}[%d additional standard or weak enemies/%d additional standard or weak enemy/%d additional standard or weak enemies]>>", i + 1),
                            (dontparse[i] ? values[i] : double.Parse(values[i]).ToString() + "*Pts additional standard or weak enemies"));
                        desc = desc.Replace(string.Format("<<{0}[%d seconds/%d second/%d seconds]>>", i + 1),
                            (dontparse[i] ? values[i] : double.Parse(values[i]).ToString() + "*Pts second(s)"));
                        desc = desc.Replace(string.Format("<<{0}[%d stacks/%d stack/%d stacks]>>", i + 1),
                            (dontparse[i] ? values[i] : double.Parse(values[i]).ToString() + "*Pts stack(s)"));
                    }
                    #endregion
                }
                #endregion
                #region Determine if this is a Rage Generating ability
                if (desc.ToLower().Contains("builds 1 rage per second")) {
                    ab.ApCost = -1 * 1 * ab.ChannelingTime;
                    ab.ApType = GomLib.Models.ApType.Rage;
                } else if (desc.ToLower().Contains("building 3 rage")) {
                    ab.ApCost = -1 * 3;
                    ab.ApType = GomLib.Models.ApType.Rage;
                } else if (desc.ToLower().Contains("building 6 rage")) {
                    ab.ApCost = -1 * 6;
                    ab.ApType = GomLib.Models.ApType.Rage;
                } else if (desc.ToLower().Contains("generates 6 rage")) {
                    ab.ApCost = -1 * 6;
                    ab.ApType = GomLib.Models.ApType.Rage;
                } else if (desc.ToLower().Contains("builds 3 rage")) {
                    ab.ApCost = -1 * 3;
                    ab.ApType = GomLib.Models.ApType.Rage;
                } else if (desc.ToLower().Contains("builds 2 rage")) {
                    ab.ApCost = -1 * 2;
                    ab.ApType = GomLib.Models.ApType.Rage;
                } else if (desc.ToLower().Contains("generate 1 rage")) {
                    ab.ApCost = -1 * 1;
                    ab.ApType = GomLib.Models.ApType.Rage;
                }
                #endregion
                //descs.Add(desc);
                writers[k].WriteLine("    /// <summary>");
                writers[k].WriteLine("    /// " + desc.Trim().Replace("\n", "\n    /// "));
                writers[k].WriteLine("    /// </summary>");
                writers[k].WriteLine("    public sealed class " + simpleName + " : ClassAbility");
                writers[k].WriteLine("    {");
                writers[k].WriteLine("        public static new string SName { get { return @\"" + ab.Name + "\"; } }");
                writers[k].WriteLine("        public static new string SDesc { get { return @\"" + desc.Trim() + "\"; } }");
                writers[k].WriteLine("        public static new string SIcon { get { return @\"" + ab.Icon + "\"; } }");
                writers[k].WriteLine("        public static new string SFqn { get { return @\"" + ab.Fqn + "\"; } }");
                writers[k].WriteLine("        public static new int SSpellId { get { return " + ab.Id + "; } }");
                writers[k].WriteLine("        public override string Name { get { return SName; } }");
                writers[k].WriteLine("        public override string Desc { get { return SDesc; } }");
                writers[k].WriteLine("        public override string Icon { get { return SIcon; } }");
                writers[k].WriteLine("        public override string Fqn { get { return SFqn; } }");
                writers[k].WriteLine("        public override int SpellId { get { return SSpellId; } }");
                writers[k].WriteLine("        /// <summary>");
                writers[k].WriteLine("        /// " + desc.Trim().Replace("\n", "\n        /// "));
                writers[k].WriteLine("        /// </summary>");
                writers[k].WriteLine("        public " + simpleName + "(CollectedCharacter collChar)");
                writers[k].WriteLine("        {");
                writers[k].WriteLine("            CollChar = collChar;");
                writers[k].WriteLine("            //");
                writers[k].WriteLine("            AbilIterator = Maintenance." + k + "_" + simpleName + ";");
                writers[k].WriteLine("            AbilityTokens = \"" + ab.AbilityTokens + "\"; // Modifies the ability in some way");
                writers[k].WriteLine("            TalentTokens = \"" + ab.TalentTokens + "\";");
                writers[k].WriteLine("            ApCost = " + ab.ApCost + ";");
                writers[k].WriteLine("            ApType = GomLib.Models.ApType." + ab.ApType + ";");
                if (ab.CastingTime != 0)    { writers[k].WriteLine("            CastingTime = " + ab.CastingTime + "f; // In Seconds"); }
                if (ab.ChannelingTime != 0) { writers[k].WriteLine("            ChannelingTime = " + ab.ChannelingTime + "f; // In Seconds"); }
                writers[k].WriteLine("            Cooldown = " + (ab.Cooldown == 0 ? 1.5f : ab.Cooldown) + "f; // In Seconds");
                if (ab.EnergyCost != 0)     { writers[k].WriteLine("            EnergyCost = " + ab.EnergyCost + ";"); }
                if (ab.ForceCost != 0)      { writers[k].WriteLine("            ForceCost = " + ab.ForceCost + ";"); }
                if (ab.GCD > 0)             { writers[k].WriteLine("            GCD = " + ab.GCD + "f;"); }
                writers[k].WriteLine("            GcdOverride = " + ab.GcdOverride.ToString().ToLower() + ";");
                writers[k].WriteLine("            IgnoreAlacrity = " + ab.IgnoreAlacrity.ToString().ToLower() + ";");
                writers[k].WriteLine("            IsHidden = " + ab.IsHidden.ToString().ToLower() + ";");
                writers[k].WriteLine("            IsPassive = " + ab.IsPassive.ToString().ToLower() + ";");
                writers[k].WriteLine("            Level = " + ab.Level + ";");
                writers[k].WriteLine("            LineOfSightCheck = " + ab.LineOfSightCheck.ToString().ToLower() + ";");
                writers[k].WriteLine("            MaxRange = " + ab.MaxRange + "f; // In Meters");
                writers[k].WriteLine("            MinRange = " + ab.MinRange + "f; // In Meters");
                writers[k].WriteLine("            ModalGroup = " + ab.ModalGroup + ";");
                //writers[k].WriteLine("            DescriptionId = " + (ab.DescriptionId << 32) + ";");
                //writers[k].WriteLine("            NameId = " + (ab.NameId << 32) + ";");
                writers[k].WriteLine("            NodeId = " + (ab.NodeId << 32) + ";");
                writers[k].WriteLine("            Pushback = " + ab.Pushback.ToString().ToLower() + ";");
                writers[k].WriteLine("            SharedCooldown = " + ab.SharedCooldown + ";");
                writers[k].WriteLine("            TargetArc = " + ab.TargetArc + ";");
                writers[k].WriteLine("            TargetArcOffset = " + ab.TargetArcOffset + ";");
                writers[k].WriteLine("            TargetRule = GomLib.Models.TargetRule." + ab.TargetRule + ";");
                if (ab.TargetRule == TargetRule.Attackable)
                {
                    var l = AbilityDamageChangesParsing(desc);
                    foreach (string s in l) { writers[k].WriteLine("            " + s); }
                }
                var d = SpecialEffectsParser(desc);
                foreach (string s in d) { writers[k].WriteLine("            " + s); }
                if (simpleName.Contains("CrushingBlow"))
                {
                    writers[k].WriteLine("            UseSecCoeff = true;");
                }
                if (DamageCoreType1 != "") {
                    writers[k].WriteLine("            DamageCoreType1 = \"" + DamageCoreType1 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier1 = " + DamageCoreMultiplier1 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff1 = " + DamageCoreCoeff1 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin1 = " + DamageCoreHPMin1 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax1 = " + DamageCoreHPMax1 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct1 = " + DamageCoreModPct1 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin1 = " + DamageCoreFlurryBlowsMin1 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax1 = " + DamageCoreFlurryBlowsMax1 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod1 = " + DamageCoreThreatMod1 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin1 = " + DamageCoreModFixedMin1 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax1 = " + DamageCoreModFixedMax1 + "f;");
                }
                if (DamageCoreType2 != "") {
                    writers[k].WriteLine("            DamageCoreType2 = \"" + DamageCoreType2 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier2 = " + DamageCoreMultiplier2 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff2 = " + DamageCoreCoeff2 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin2 = " + DamageCoreHPMin2 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax2 = " + DamageCoreHPMax2 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct2 = " + DamageCoreModPct2 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin2 = " + DamageCoreFlurryBlowsMin2 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax2 = " + DamageCoreFlurryBlowsMax2 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod2 = " + DamageCoreThreatMod2 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin2 = " + DamageCoreModFixedMin2 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax2 = " + DamageCoreModFixedMax2 + "f;");
                }
                if (DamageCoreType3 != "")
                {
                    writers[k].WriteLine("            DamageCoreType3 = \"" + DamageCoreType3 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier3 = " + DamageCoreMultiplier3 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff3 = " + DamageCoreCoeff3 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin3 = " + DamageCoreHPMin3 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax3 = " + DamageCoreHPMax3 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct3 = " + DamageCoreModPct3 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin3 = " + DamageCoreFlurryBlowsMin3 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax3 = " + DamageCoreFlurryBlowsMax3 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod3 = " + DamageCoreThreatMod3 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin3 = " + DamageCoreModFixedMin3 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax3 = " + DamageCoreModFixedMax3 + "f;");
                }
                if (DamageCoreType4 != "")
                {
                    writers[k].WriteLine("            DamageCoreType4 = \"" + DamageCoreType4 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier4 = " + DamageCoreMultiplier4 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff4 = " + DamageCoreCoeff4 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin4 = " + DamageCoreHPMin4 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax4 = " + DamageCoreHPMax4 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct4 = " + DamageCoreModPct4 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin4 = " + DamageCoreFlurryBlowsMin4 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax4 = " + DamageCoreFlurryBlowsMax4 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod4 = " + DamageCoreThreatMod4 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin4 = " + DamageCoreModFixedMin4 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax4 = " + DamageCoreModFixedMax4 + "f;");
                }
                if (DamageCoreType5 != "")
                {
                    writers[k].WriteLine("            DamageCoreType5 = \"" + DamageCoreType5 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier5 = " + DamageCoreMultiplier5 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff5 = " + DamageCoreCoeff5 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin5 = " + DamageCoreHPMin5 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax5 = " + DamageCoreHPMax5 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct5 = " + DamageCoreModPct5 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin5 = " + DamageCoreFlurryBlowsMin5 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax5 = " + DamageCoreFlurryBlowsMax5 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod5 = " + DamageCoreThreatMod5 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin5 = " + DamageCoreModFixedMin5 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax5 = " + DamageCoreModFixedMax5 + "f;");
                }
                if (DamageCoreType6 != "")
                {
                    writers[k].WriteLine("            DamageCoreType6 = \"" + DamageCoreType6 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier6 = " + DamageCoreMultiplier6 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff6 = " + DamageCoreCoeff6 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin6 = " + DamageCoreHPMin6 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax6 = " + DamageCoreHPMax6 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct6 = " + DamageCoreModPct6 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin6 = " + DamageCoreFlurryBlowsMin6 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax6 = " + DamageCoreFlurryBlowsMax6 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod6 = " + DamageCoreThreatMod6 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin6 = " + DamageCoreModFixedMin6 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax6 = " + DamageCoreModFixedMax6 + "f;");
                }
                if (DamageCoreType7 != "")
                {
                    writers[k].WriteLine("            DamageCoreType7 = \"" + DamageCoreType7 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier7 = " + DamageCoreMultiplier7 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff7 = " + DamageCoreCoeff7 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin7 = " + DamageCoreHPMin7 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax7 = " + DamageCoreHPMax7 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct7 = " + DamageCoreModPct7 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin7 = " + DamageCoreFlurryBlowsMin7 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax7 = " + DamageCoreFlurryBlowsMax7 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod7 = " + DamageCoreThreatMod7 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin7 = " + DamageCoreModFixedMin7 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax7 = " + DamageCoreModFixedMax7 + "f;");
                }
                if (DamageCoreType8 != "")
                {
                    writers[k].WriteLine("            DamageCoreType8 = \"" + DamageCoreType8 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier8 = " + DamageCoreMultiplier8 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff8 = " + DamageCoreCoeff8 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin8 = " + DamageCoreHPMin8 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax8 = " + DamageCoreHPMax8 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct8 = " + DamageCoreModPct8 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin8 = " + DamageCoreFlurryBlowsMin8 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax8 = " + DamageCoreFlurryBlowsMax8 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod8 = " + DamageCoreThreatMod8 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin8 = " + DamageCoreModFixedMin8 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax8 = " + DamageCoreModFixedMax8 + "f;");
                }
                if (DamageCoreType9 != "")
                {
                    writers[k].WriteLine("            DamageCoreType9 = \"" + DamageCoreType9 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier9 = " + DamageCoreMultiplier9 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff9 = " + DamageCoreCoeff9 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin9 = " + DamageCoreHPMin9 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax9 = " + DamageCoreHPMax9 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct9 = " + DamageCoreModPct9 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin9 = " + DamageCoreFlurryBlowsMin9 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax9 = " + DamageCoreFlurryBlowsMax9 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod9 = " + DamageCoreThreatMod9 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin9 = " + DamageCoreModFixedMin9 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax9 = " + DamageCoreModFixedMax9 + "f;");
                }
                if (DamageCoreType10 != "")
                {
                    writers[k].WriteLine("            DamageCoreType10 = \"" + DamageCoreType10 + "\";");
                    writers[k].WriteLine("            DamageCoreMultiplier10 = " + DamageCoreMultiplier10 + "f;");
                    writers[k].WriteLine("            DamageCoreCoeff10 = " + DamageCoreCoeff10 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMin10 = " + DamageCoreHPMin10 + "f;");
                    writers[k].WriteLine("            DamageCoreHPMax10 = " + DamageCoreHPMax10 + "f;");
                    writers[k].WriteLine("            DamageCoreModPct10 = " + DamageCoreModPct10 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMin10 = " + DamageCoreFlurryBlowsMin10 + "f;");
                    writers[k].WriteLine("            DamageCoreFlurryBlowsMax10 = " + DamageCoreFlurryBlowsMax10 + "f;");
                    writers[k].WriteLine("            DamageCoreThreatMod10 = " + DamageCoreThreatMod10 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMin10 = " + DamageCoreModFixedMin10 + "f;");
                    writers[k].WriteLine("            DamageCoreModFixedMax10 = " + DamageCoreModFixedMax10 + "f;");
                }
                if (HealingCoreHPMin != 0)
                {
                    writers[k].WriteLine("            HealingCoreMultiplier = " + HealingCoreMultiplier + "f;");
                    writers[k].WriteLine("            HealingCoreHPMin = " + HealingCoreHPMin + "f;");
                    writers[k].WriteLine("            HealingCoreHPMax = " + HealingCoreHPMax + "f;");
                }
                if (HealingCoreHPMin2 != 0) {
                    writers[k].WriteLine("            HealingCoreMultiplier = " + HealingCoreMultiplier2 + "f;");
                    writers[k].WriteLine("            HealingCoreCoeff = " + HealingCoreCoeff2 + "f;");
                    writers[k].WriteLine("            HealingCoreHPMin = " + HealingCoreHPMin2 + "f;");
                    writers[k].WriteLine("            HealingCoreHPMax = " + HealingCoreHPMax2 + "f;");
                }
                if (Duration != 0) { writers[k].WriteLine("            Duration = " + Duration + "f;"); }
                if (Rank != 0) { writers[k].WriteLine("            // Talent Rank = " + Rank + "f;"); }
                writers[k].WriteLine("            //");
                writers[k].WriteLine("            Initialize();");
                writers[k].WriteLine("        }");
                writers[k].WriteLine("    }");
            }
            #endregion
            #region Write Maintenance Enum to "all" file
            writers["all"].WriteLine("    #region Maintenance");
            writers["all"].WriteLine("    public enum Maintenance");
            writers["all"].WriteLine("    {");
            abilsReadAlready.Clear();
            foreach (Ability ab in abilityList)
            {
            string k = (ab.Fqn.Contains('.') ? (ab.Fqn.Contains(".flurry.") ? ab.Fqn.Split('.')[2] : ab.Fqn.Split('.')[1]) : k = ab.Fqn);
            string simpleName = GetSimpleName(ab.Name);
            if (abilsReadAlready.Contains(k + "_" + simpleName)) {
            simpleName += (abilsReadAlready.Where(i => i == (k + "_" + simpleName)).Count() + 1);
            }
            abilsReadAlready.Add((k + "_" + simpleName).Clone() as string);
            writers["all"].WriteLine("        " + k + "_" + simpleName + ",");
            }
            writers["all"].WriteLine("    };");
            writers["all"].WriteLine("    #endregion // Maintenance");
            #endregion
            #region Write Static List to "all" file
            writers["all"].WriteLine("    #region Static List");
            writers["all"].WriteLine("    public static class HelperFunction {");
            writers["all"].WriteLine("        public static readonly List<Type> ALL_CLASSABILITIES_TYPES = new List<Type>() {");
            abilsReadAlready.Clear();
            foreach (Ability ab in abilityList)
            {
                string k = (ab.Fqn.Contains('.') ? (ab.Fqn.Contains(".flurry.") ? ab.Fqn.Split('.')[2] : ab.Fqn.Split('.')[1]) : k = ab.Fqn);
                string simpleName = GetSimpleName(ab.Name);
                if (abilsReadAlready.Contains(k + "." + simpleName))
                {
                simpleName += (abilsReadAlready.Where(i => i == (k + "." + simpleName)).Count() + 1);
                }
                abilsReadAlready.Add((k + "." + simpleName).Clone() as string);
                writers["all"].WriteLine("            typeof(" + k + "." + simpleName + "),");
            }
            writers["all"].WriteLine("        };");
            writers["all"].WriteLine("    }");
            writers["all"].WriteLine("    #endregion // Static List");
            #endregion
            #region Write Footer to every file
            foreach (string k in abilLists.Keys)
            {
                if (k != "all") {
                    writers[k].WriteLine("    #endregion // " + k);
                }
                writers[k].WriteLine("}");
                writers[k].WriteLine("");
            }
            #endregion
            // end writing file
            foreach (string k in abilLists.Keys)
            {
                writers[k].Close();
                writers[k].Dispose();
                outFiles[k].Close();
                outFiles[k].Dispose();
            }
            Dispatcher.BeginInvoke((Action)delegate
            {
                TB_AbilityClassFile.Text = "";
            });
            /*foreach (string k in abilLists.Keys)
            {
                using (var fs = System.IO.File.Open(outFilePaths[k], System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Read))
                {
                    using (System.IO.StreamReader sr = new System.IO.StreamReader(fs))
                    {
                        string s = sr.ReadToEnd();
                        Dispatcher.BeginInvoke((Action)delegate
                        {
                            TB_AbilityClassFile.Text += s;
                        });
                    }
                }
            }*/
        }

        // Completed Method
        private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled) {
                DG_ProgressBar.statusText.Text = "Cancelled";
            } else if (e.Error != null) {
                DG_ProgressBar.statusText.Text = "Exception Thrown";
            } else {
                DG_ProgressBar.statusText.Text = "Completed";
            }
            Dispatcher.BeginInvoke((Action)delegate
            {
                DG_ProgressBar.FinishProgress();
            });
            //DG_ProgressBar.BT_Cancel.IsEnabled = false;
            Dispatcher.BeginInvoke((Action)delegate
            {
                AbilityGrid.ItemsSource = view;
            });
            
        }

        private void DG_ProgressBar_Closed(object sender, EventArgs e)
        {
            LB_Count.Text = DG_ProgressBar.TB_Perc.Text;
        }

        private void BT_ExtractImages_Click(object sender, RoutedEventArgs e)
        {
            TorLib.Icons.SaveTo(System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), @"images\"), true);
            //TorLib.Icons.ConvertDDSToJPG();
        }

        private Dictionary<object, Exception> errors = new Dictionary<object, Exception>();

        private void OKButton_Click(object sender, RoutedEventArgs e) { this.DialogResult = true; }
    }
}

